/* 向线程传递参数饼返回值
 * 线程的创建者在创建线程时可能会用指向void的指针给线程传递单个参数。
 * 要传递多个值，创建者必须使用指向数组或结构的指针
 * 该程序中说明了如何传递一个指向数组的指针。main程序将包含两个打开的文件描述
 * 的数组传递给一个运行copyfilenmalloc函数的线程
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "restart.h"

#define PERMS (S_IRUSR | S_IWUSR)
#define READ_FLAGS O_RDONLY
#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)

void *copyfilemalloc(void *arg);

/* 将fromfile复制到tofile*/
int main (int argc, char *argv[]) {
    int *bytesptr;
    int error;
    int fds[2];
    pthread_t tid;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s fromfile tofile\n", argv[0]);
        return 1;
    }

    if ((fds[0] = open(argv[1], READ_FLAGS) == -1 ) ||
        (fds[1] = open(argv[2],WRITE_FLAGS) == -1) ) {
            perror("Failed to open the files");
            return 1;
        }
    
    /* 创建线程*/
    if (error = pthread_create(&tid, NULL, copyfilemalloc, fds)) {
        fprintf(stderr, "Failed to create thread: %s\n", strerror(error));
        return 1;
    }

    /* 将线程阻塞*/
    if (error = pthread_join(tid, (void **)&bytesptr)) {
        fprintf(stderr, "Failed to join thread: %s\n", strerror(error));
        return 1;
    }

    printf("Number of bytes copied: %d\n", *bytesptr);
    return 0;
}

/* copyfilemalloc函数的实现，通过这个函数将一个文件的内容复制到另一个文件中
   它通过为返回值动态分配空间返回复制的字节数*/
// 将infd复制到带有返回值的outfd中
// 参数arg中保存的是一个指针，这个指针指向一对表示源和目标文件的打开的描述符。变量bytesp
// infd和outfd是在copyfilemalloc的局部栈上分配的，不能被其他线程直接访问。
void *copyfilemalloc(void *arg) {
    int *bytesp;
    int infd;
    int outfd;

    infd = *((int *)arg);
    outfd = *((int *)arg + 1);

    if ( (bytesp = (int *)malloc(sizeof(int))) == NULL )
        return NULL;
    
    *bytesp = copyfile(infd, outfd);

    close(infd);
    close(outfd);

    // POSIX要去malloc是线程安全的，copyfilemalloc函数返回bytesp指针，这等价于调用pthread_exit函数。
    // 使用完后释放这个空间是调用程序（callcopymalloc）的责任。在这种情况下，程序会终止，因此就不需要调用free了。
    return bytesp;
}